﻿using System;
using System.Collections.Generic;
using HK.Editor.GUIEx.Protocol.Drag;
using UnityEditor;
using UnityEngine;

namespace HK.Editor.GUIEx.Drag
{
    /// <summary>
    /// 拖拽元素
    /// </summary>
    public class DragElement : IDragElement
    {
        /// <summary>
        /// Property
        /// </summary>
        public SerializedProperty Property { get; set; } = null;

        /// <summary>
        /// 开始索引
        /// </summary>
        public int StartIndex { get; set; } = 0;

        /// <summary>
        /// 拖拽偏移
        /// </summary>
        public float DragOffset { get; set; } = 0;

        /// <summary>
        /// 选中标志位
        /// </summary>
        public bool Selected { get; set; } = false;
			
        /// <summary>
        /// 矩形区域
        /// </summary>
        public Rect Rect { get; set; } = Rect.zero;
        
        /// <summary>
        /// 希望拖拽区域
        /// </summary>
        public Rect DesiredRect { get; set; } = Rect.zero;

        /// <summary>
        /// 展开标志位
        /// </summary>
        private bool _isExpanded = false;
        
        /// <summary>
        /// 状态
        /// <para>* Key : Drag Element索引</para>
        /// <para>* Value : 展开标志位</para>
        /// </summary>
        private Dictionary<int, bool> _states;
        
        /// <summary>
        /// 重叠校验
        /// </summary>
        /// <param name="iCurRect">当前矩形区域</param>
        /// <param name="iIndex">索引</param>
        /// <param name="iDirection"></param>
        /// <returns>true:重叠; false:不重叠;</returns>
        public bool Overlaps(Rect iCurRect, int iIndex, int iDirection) 
        {

            if (iDirection < 0 && iIndex < StartIndex) 
            {
                return DesiredRect.yMin < iCurRect.center.y;
            }

            if (iDirection > 0 && iIndex > StartIndex) 
            {
                return DesiredRect.yMax > iCurRect.center.y;
            }

            return false;
        }
        
        /// <summary>
        /// 记录/采样 拖拽元素列表状态
        /// </summary>
        public void RecordState() 
        {
            _states = new Dictionary<int, bool>();
            _isExpanded = Property.isExpanded;

            // 迭代
            Iterate(this, Property, 
                (DragElement iDragElement, SerializedProperty iElementProperty, int iIndex) => 
                {
                    iDragElement._states[iIndex] = iElementProperty.isExpanded; 
                });
        }
        
        /// <summary>
        /// 恢复状态
        /// </summary>
        /// <param name="iProperty">Property</param>
        public void RestoreState(SerializedProperty iProperty) 
        {
            if(null == iProperty) return;
            iProperty.isExpanded = _isExpanded;

            Iterate(this, iProperty, (iDragElement, iElementProperty, iIndex) => 
            {
                iElementProperty.isExpanded = iDragElement._states[iIndex];
            });
        }
        
        /// <summary>
        /// 迭代
        /// </summary>
        /// <param name="iDragElement">Drop Element</param>
        /// <param name="iProperty">Property</param>
        /// <param name="iAction">Action</param>
        private static void Iterate(DragElement iDragElement, SerializedProperty iProperty, 
            System.Action<DragElement, SerializedProperty, int> iAction) {

            var copy = iProperty.Copy();
            var end = copy.GetEndProperty();

            var index = 0;
            while (copy.NextVisible(true) && !SerializedProperty.EqualContents(copy, end)) 
            {
                if (copy.hasVisibleChildren) 
                {
                    iAction(iDragElement, copy, index);
                    index++;
                }
            }
        }
    }
    
    /// <summary>
    /// 拖拽区域列表
    /// </summary>
    public sealed class DragRectsList : IDragRectsList
    {

#region Create

        /// <summary>
        /// 创建拖拽区域列表
        /// </summary>
        /// <param name="iLength">长度</param>
        /// <returns>拖拽区域列表</returns>
        public static IDragRectsList Create(int iLength)
        {
            return new DragRectsList()
            {
                _length = iLength, _startIndex = 0,
                _elements = new IDragElement[iLength]
            };
        }

#endregion
        
        /// <summary>
        /// 保护构造函数
        /// </summary>
        private DragRectsList() {}
        
        private int _startIndex = 0;
        /// <summary>
        /// 开始索引
        /// </summary>
        public int StartIndex => _startIndex;
        
        private int _length;
        /// <summary>
        /// 长度
        /// </summary>
        public int Length => _length;
        
        private IDragElement[] _elements;
        /// <summary>
        /// 拖拽Element列表
        /// </summary>
        public IDragElement[] Elements 
        {
            get => _elements;
            set => _elements = value;
        }
        
        /// <summary>
        /// 下表
        /// </summary>
        /// <param name="iIndex">索引</param>
        public IDragElement this[int iIndex] 
        {
            get => _elements[iIndex];
            set => _elements[iIndex] = value;
        }
        
        /// <summary>
        /// 重置尺寸
        /// </summary>
        /// <param name="iStart">开始索引</param>
        /// <param name="iLength">长度</param>
        public void Resize(int iStart, int iLength) 
        {
            _startIndex = iStart;
            _length = iLength;

            if (_elements.Length != iLength) 
            {
                Array.Resize(ref _elements, iLength);
            }
        }
        
        /// <summary>
        /// 根据索引排序
        /// </summary>
        public void SortByIndex() 
        {

            Array.Sort(_elements, (iA, iB) => 
            {
                if (iB.Selected) 
                {
                    return iA.Selected ? iA.StartIndex.CompareTo(iB.StartIndex) : 1;
                }

                if (iA.Selected) 
                {
                    return iB.Selected ? iB.StartIndex.CompareTo(iA.StartIndex) : -1;
                }

                return iA.StartIndex.CompareTo(iB.StartIndex);
            });
        }
        
        /// <summary>
        /// 记录/采样 拖拽元素列表状态
        /// </summary>
        public void RecordState() 
        {
            for (var i = 0; i < _length; ++i)
            {
                _elements[i].RecordState();
            }
        }
        
        /// <summary>
        /// 回复列表状态
        /// </summary>
        /// <param name="iList">列表</param>
        public void RestoreState(SerializedProperty iList) 
        {
            for (var i = 0; i < _length; ++i) 
            {
                _elements[i].RestoreState(iList.GetArrayElementAtIndex(i + _startIndex));
            }
        }
        
        /// <summary>
        /// 根据位置排序
        /// </summary>
        public void SortByPosition() 
        {
            Array.Sort(_elements, (iA, iB) => iA.DesiredRect.center.y.CompareTo(iB.DesiredRect.center.y));
        }

        public int GetIndexFromSelection(int iIndex) 
        {
            return Array.FindIndex(_elements, iDragElement => iDragElement.StartIndex == iIndex);
        }
    }
}
